/**
 * Copyright 2014 ABSir's Studio
 * 
 * All right reserved
 *
 * Create on 2014年11月21日 下午2:32:18
 */
package com.absir.appserv.game.service;

import java.util.List;

import org.hibernate.Session;

import com.absir.appserv.data.value.DataQuery;
import com.absir.appserv.game.bean.JbFriend;
import com.absir.appserv.game.bean.JbPlayer;
import com.absir.appserv.game.context.JbPlayerContext;
import com.absir.appserv.game.context.PlayerServiceBase;
import com.absir.appserv.jdbc.JdbcPage;
import com.absir.appserv.system.bean.JEmbedLL;
import com.absir.appserv.system.dao.BeanDao;
import com.absir.appserv.system.dao.utils.QueryDaoUtils;
import com.absir.bean.basis.Base;
import com.absir.bean.core.BeanFactoryUtils;
import com.absir.bean.inject.value.Bean;
import com.absir.core.kernel.KernelLang.CallbackTemplate;
import com.absir.orm.transaction.value.Transaction;
import com.absir.server.exception.ServerException;
import com.absir.server.exception.ServerStatus;

/**
 * @author absir
 *
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
@Base
@Bean
public abstract class FriendService {

	/** 对象单例访问 */
	public static final FriendService ME = BeanFactoryUtils.get(FriendService.class);

	/**
	 * 获取好友列表
	 * 
	 * @param playerId
	 * @param jdbcPage
	 * @return
	 */
	@DataQuery(value = "SELECT o FROM JFriend o WHERE o.id.eid = ? AND o.follow = TRUE AND o.targetFollow = TRUE")
	protected abstract List<? extends JbFriend> getFriends(Long playerId, JdbcPage jdbcPage);

	/**
	 * 获取好友申请列表
	 * 
	 * @param playerId
	 * @param jdbcPage
	 * @return
	 */
	@DataQuery(value = "SELECT o FROM JFriend o WHERE o.id.eid = ? AND o.follow = FALSE AND o.targetFollow = TRUE")
	protected abstract List<? extends JbFriend> getFriendings(Long playerId, JdbcPage jdbcPage);

	/**
	 * 获取关注列表
	 * 
	 * @param playerId
	 * @param jdbcPage
	 * @return
	 */
	@DataQuery(value = "SELECT o FROM JFriend o WHERE o.id.eid = ? AND o.follow = TRUE")
	protected abstract List<? extends JbFriend> getFollowings(Long playerId, JdbcPage jdbcPage);

	/**
	 * 获取被关注列表
	 * 
	 * @param playerId
	 * @param jdbcPage
	 * @return
	 */
	@DataQuery(value = "SELECT o FROM JFriend o WHERE o.id.eid = ? AND o.targetFollow = TRUE")
	protected abstract List<? extends JbFriend> getFollowers(Long playerId, JdbcPage jdbcPage);

	/**
	 * 获取好友列表
	 * 
	 * @param playerId
	 * @param pageIndex
	 * @return
	 */
	@Transaction(readOnly = true)
	public List<? extends JbPlayer> getFriendPlayers(Long playerId, JdbcPage jdbcPage) {
		List<? extends JbFriend> friends = FriendService.ME.getFriends(playerId, jdbcPage);
		return getFriendPlayers(playerId, friends);
	}

	/**
	 * 获取好友申请列表
	 * 
	 * @param playerId
	 * @param jdbcPage
	 * @return
	 */
	public List<? extends JbPlayer> getFriendingPlayers(Long playerId, JdbcPage jdbcPage) {
		List<? extends JbFriend> friends = FriendService.ME.getFriendings(playerId, jdbcPage);
		return getFriendPlayers(playerId, friends);
	}

	/**
	 * 获取关注列表
	 * 
	 * @param playerId
	 * @param jdbcPage
	 * @return
	 */
	@Transaction(readOnly = true)
	public List<? extends JbPlayer> getFollowingPlayers(Long playerId, JdbcPage jdbcPage) {
		List<? extends JbFriend> friends = FriendService.ME.getFollowings(playerId, jdbcPage);
		return getFriendPlayers(playerId, friends);
	}

	/**
	 * 获取被关注列表
	 * 
	 * @param playerId
	 * @param jdbcPage
	 * @return
	 */
	@Transaction(readOnly = true)
	public List<? extends JbPlayer> getFollowerPlayers(Long playerId, JdbcPage jdbcPage) {
		List<? extends JbFriend> friends = FriendService.ME.getFollowers(playerId, jdbcPage);
		return getFriendPlayers(playerId, friends);
	}

	/**
	 * 好友在线状态
	 * 
	 * @param playerId
	 * @param friends
	 * @return
	 */
	public List<? extends JbPlayer> getFriendPlayers(Long playerId, List<? extends JbFriend> friends) {
		List<JbPlayer> players = (List<JbPlayer>) (Object) friends;
		JbFriend friend;
		int size = friends.size();
		for (int i = 0; i < size; i++) {
			friend = friends.get(i);
			players.set(i, JbPlayerContext.COMPONENT.onlinePlayer(friend.getTargetPlayer()));
		}

		return players;
	}

	/**
	 * 获取系统推荐
	 * 
	 * @param playerId
	 * @return
	 */
	@Transaction(readOnly = true)
	public List<? extends JbPlayer> getRecommends(JbPlayer player) {
		return getRecommends(player, 20);
	}

	/**
	 * @param player
	 * @param count
	 * @return
	 */
	@Transaction(readOnly = true)
	public List<? extends JbPlayer> getRecommends(JbPlayer player, int count) {
		Long playerId = player.getId();
		int level = player.getLevel();
		List<JbPlayer> players = QueryDaoUtils
				.createQueryArray(
						BeanDao.getSession(),
						"SELECT o FROM JPlayer o WHERE o.id != ? AND o.id NOT IN (SELECT o.id.mid FROM JFriend o WHERE o.id.eid = ? AND o.follow = TRUE) AND o.serverId = ? AND o.card != 0 AND o.level >= ? AND o.level <= ? ORDER BY RAND()",
						playerId, playerId, player.getServerId(), level - 5, level + 5).setMaxResults(count).list();
		return JbPlayerContext.COMPONENT.onlinePlayers(players);
	}

	/**
	 * 搜索玩家
	 * 
	 * @param playerId
	 * @param serverId
	 * @param name
	 * @param jdbcPage
	 * @return
	 */
	@DataQuery(value = "SELECT o FROM JPlayer o WHERE o.id != ? AND o.serverId = ? AND o.name like ?")
	protected abstract List<? extends JbPlayer> searchPlayers(Long playerId, Long serverId, String name, JdbcPage jdbcPage);

	/**
	 * @param playerId
	 * @param name
	 * @param jdbcPage
	 * @return
	 */
	@Transaction(readOnly = true)
	public Object searchFriends(JbPlayer player, String name, JdbcPage jdbcPage) {
		return searchPlayers(player.getId(), player.getServerId(), '%' + name + '%', jdbcPage);
	}

	/**
	 * 获取好友关系
	 * 
	 * @param playerId
	 * @param targetId
	 * @return
	 */
	public JbFriend getFriend(Session session, Long playerId, Long targetId) {
		JEmbedLL embedLL = new JEmbedLL();
		embedLL.setEid(playerId);
		embedLL.setMid(targetId);
		return BeanDao.get(session, JbPlayerContext.COMPONENT.FRIEND_CLASS, embedLL);
	}

	/**
	 * 获取好友关系
	 * 
	 * @param session
	 * @param player
	 * @param targetPlayer
	 * @return
	 */
	public JbFriend getFriendForce(Session session, JbPlayer player, JbPlayer targetPlayer) {
		JEmbedLL embedLL = new JEmbedLL();
		embedLL.setEid(player.getId());
		embedLL.setMid(targetPlayer.getId());
		JbFriend friend = BeanDao.get(session, JbPlayerContext.COMPONENT.FRIEND_CLASS, embedLL);
		if (friend == null) {
			friend = JbPlayerContext.COMPONENT.createFriend();
			friend.setId(embedLL);
			friend.setTargetPlayer(targetPlayer);
			try {
				session.persist(friend);
				session.flush();

			} catch (Exception e) {
			}

			friend = BeanDao.get(session, "JFriend", JbFriend.class, embedLL);
			JEmbedLL targetEmbedLL = new JEmbedLL();
			targetEmbedLL.setEid(targetPlayer.getId());
			targetEmbedLL.setMid(player.getId());
			JbFriend targetFriend = BeanDao.get(session, JbPlayerContext.COMPONENT.FRIEND_CLASS, targetEmbedLL);
			if (targetFriend == null) {
				targetFriend = JbPlayerContext.COMPONENT.createFriend();
				targetFriend.setId(targetEmbedLL);
				targetFriend.setTargetPlayer(player);
				try {
					session.persist(targetFriend);
					session.flush();

				} catch (Exception e) {
				}
			}

			session.evict(targetFriend);
		}

		session.evict(friend);
		return friend;
	}

	/**
	 * 是否是好友
	 * 
	 * @param player
	 * @param targetPlayer
	 * @return
	 */
	@Transaction(readOnly = true)
	public boolean isFriend(JbPlayer player, JbPlayer targetPlayer) {
		JbFriend friend = getFriend(BeanDao.getSession(), player.getId(), targetPlayer.getId());
		return friend != null && friend.isFollow() && friend.isTargetFollow();
	}

	/**
	 * 添加好友
	 * 
	 * @param player
	 * @param done
	 * @return
	 */
	protected boolean addFriend(JbPlayer player, boolean done) {
		if (player.getFriendNumber() >= player.getMaxFriendNumber()) {
			return false;
		}

		if (done) {
			player.setFriendNumber(player.getFriendNumber() + 1);
		}

		return true;
	}

	/**
	 * 添加好友
	 * 
	 * @param playerContext
	 * @param targetId
	 */
	@Transaction
	public int addFriend(final JbPlayerContext playerContext, final Long targetId) {
		final int[] res = new int[1];
		PlayerServiceBase.ME.doPlayerTarget(playerContext.getPlayer().getId(), targetId, new Runnable() {

			@Override
			public void run() {
				res[0] = ME.doAddFriend(playerContext, targetId);
			}
		});

		return res[0];
	}

	/**
	 * 执行添加好友
	 * 
	 * @param playerContext
	 * @param targetId
	 * @return
	 */
	@Transaction
	protected int doAddFriend(JbPlayerContext playerContext, Long targetId) {
		JbPlayer player = playerContext.getPlayer();
		Long playerId = player.getId();
		if (!addFriend(player, false) || playerId.equals(targetId)) {
			throw new ServerException(ServerStatus.ON_DENIED);
		}

		JbPlayer targetPlayer = PlayerServiceBase.ME.findPlayer(targetId);
		if (targetPlayer == null || !addFriend(targetPlayer, false) || targetPlayer.getServerId() != player.getServerId()) {
			throw new ServerException(ServerStatus.ON_DENIED);
		}

		Session session = BeanDao.getSession();
		JbFriend friend = getFriendForce(session, player, targetPlayer);
		if (friend.isFollow()) {
			return 0;
		}

		QueryDaoUtils.createQueryArray(session, "UPDATE JFriend o SET o.follow = TRUE WHERE o.id.eid = ? AND o.id.mid = ?",
				playerId, targetId).executeUpdate();
		QueryDaoUtils.createQueryArray(session, "UPDATE JFriend o SET o.targetFollow = TRUE WHERE o.id.eid = ? AND o.id.mid = ?",
				targetId, playerId).executeUpdate();
		if (friend.isTargetFollow()) {
			addFriendDone(playerContext, targetId);
		}

		return 1;
	}

	/**
	 * 添加好友数量变更
	 * 
	 * @param playerContext
	 * @param targetId
	 */
	protected void addFriendDone(final JbPlayerContext playerContext, final Long targetId) {
		PlayerServiceBase.ME.modifyPlayer(targetId, new CallbackTemplate<JbPlayer>() {

			@Override
			public void doWith(JbPlayer template) {
				addFriend(template, true);
				addFriend(playerContext.getPlayer(), true);
			}
		});
	}

	/**
	 * 删除好友
	 * 
	 * @param playerContext
	 * @param target
	 */
	public int removeFriend(final JbPlayerContext playerContext, final Long targetId) {
		final int[] res = new int[1];
		PlayerServiceBase.ME.doPlayerTarget(playerContext.getPlayer().getId(), targetId, new Runnable() {

			@Override
			public void run() {
				res[0] = ME.doRemoveFriend(playerContext, targetId);
			}
		});

		return res[0];
	}

	/**
	 * 执行删除好友
	 * 
	 * @param playerContext
	 * @param targetId
	 * @return
	 */
	@Transaction
	protected int doRemoveFriend(JbPlayerContext playerContext, final Long targetId) {
		Session session = BeanDao.getSession();
		Long playerId = playerContext.getPlayer().getId();
		JbFriend friend = getFriend(session, playerId, targetId);
		if (friend != null) {
			if (friend.isFollow() && couldeDeleteFriend(friend)) {
				QueryDaoUtils.createQueryArray(session,
						"UPDATE JFriend o SET o.follow = FALSE WHERE o.id.eid = ? AND o.id.mid = ?", playerId, targetId)
						.executeUpdate();
				QueryDaoUtils.createQueryArray(session,
						"UPDATE JFriend o SET o.targetFollow = FALSE WHERE o.id.eid = ? AND o.id.mid = ?", targetId, playerId)
						.executeUpdate();
				if (friend.isTargetFollow()) {
					removeFriendDone(playerContext, targetId);
				}
			}

			return 1;
		}

		return 0;
	}

	/**
	 * 删除好友条件
	 * 
	 * @param friend
	 * @return
	 */
	protected boolean couldeDeleteFriend(JbFriend friend) {
		return true;
	}

	/**
	 * 删除好友数量变更
	 * 
	 * @param playerContext
	 * @param targetId
	 */
	protected void removeFriendDone(final JbPlayerContext playerContext, Long targetId) {
		PlayerServiceBase.ME.modifyPlayer(targetId, new CallbackTemplate<JbPlayer>() {

			@Override
			public void doWith(JbPlayer template) {
				template.setFriendNumber(template.getFriendNumber() - 1);
				playerContext.modifyFriendNumber(-1);
			}
		});
	}
}
